#region Using directives

using System;
using System.IO;
using System.Drawing;
using System.Drawing.Imaging;
using System.Reflection;
using System.Windows.Forms;
using System.Collections;

using FighterChessEngine.Enum;
using FighterChessEngine.FC_Board;
using FighterChessEngine.FC_Fighter;
using FighterChessEngine.FC_Fighter.Fighters;

using FighterChessSkin.FC_Board;

#endregion

namespace FighterChessSkin.FC_Fighter
{
    /// <summary>
    /// Summary description for UIFighter.
    /// </summary>
    public class UIFighter
    {
        #region Atributes
        protected readonly string appDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().GetName().CodeBase);
        protected readonly int topReserve = 24;
        protected readonly int height = 27;
        protected readonly int width = 27;

        protected readonly string dirWPawn = "Images\\Fighters\\WPawn";
        protected readonly string dirBPawn = "Images\\Fighters\\BPawn";
        protected readonly string dirWRook = "Images\\Fighters\\WRook";
        protected readonly string dirBRook = "Images\\Fighters\\BRook";
        protected readonly string dirWKnight = "Images\\Fighters\\WKnight";
        protected readonly string dirBKnight = "Images\\Fighters\\BKnight";
        protected readonly string dirWBishop = "Images\\Fighters\\WBishop";
        protected readonly string dirBBishop = "Images\\Fighters\\BBishop";
        protected readonly string dirWKing = "Images\\Fighters\\WKing";
        protected readonly string dirBKing = "Images\\Fighters\\BKing";
        protected readonly string dirWQueen = "Images\\Fighters\\WQueen";
        protected readonly string dirBQueen = "Images\\Fighters\\BQueen";

        protected string dirWFighter = "";
        protected string dirBFighter = "";

        protected Point location; // bottom-left
        protected Fighter fighter;
        private Graphics gOff;
        protected Bitmap bmpBoard; // without this UIFighter

        protected Timer actionTimer = new Timer();
        protected Timer imgTimer = new Timer();
        protected Point oldLocation; // bottom-left
        protected Point newLocation; // bottom-left
        protected int step = 3;
        protected int deltaX;
        protected int deltaY;

        protected Bitmap img = null;
        protected int imgIndex = 0;
        protected int moveFrames = 0;
        #endregion

        #region Properties
        public Graphics Graphic
        {
            get { return gOff; }
            set { gOff = value; }
        }
        #endregion

        #region Methods
        public UIFighter()
        {
        }

        public UIFighter(Fighter fighter, Graphics gOff)
            : this()
        {
            this.fighter = fighter;
            this.location = CalculateFighterCoordinate(fighter.CurrentPos.Row, fighter.CurrentPos.Col);
            this.gOff = gOff;

            switch (fighter.Type)
            {
                case FighterType.Pawn:
                    dirBFighter = dirBPawn;
                    dirWFighter = dirWPawn;
                    break;
                case FighterType.Bishop:
                    dirBFighter = dirBBishop;
                    dirWFighter = dirWBishop;
                    break;
                case FighterType.King:
                    dirBFighter = dirBKing;
                    dirWFighter = dirWKing;
                    break;
                case FighterType.Knight:
                    dirBFighter = dirBKnight;
                    dirWFighter = dirWKnight;
                    break;
                case FighterType.Queen:
                    dirBFighter = dirBQueen;
                    dirWFighter = dirWQueen;
                    break;
                case FighterType.Rook:
                    dirBFighter = dirBRook;
                    dirWFighter = dirWRook;
                    break;
                default: break;
            }
        }

        public void StandUp()
        {
            DrawStandStance();
        }

        public void SitDown()
        {
            DrawSitStance();
        }

        public void ShowNextPosByFlashSquare(UISquare[,] uiSquares)
        {
            foreach (Square s in fighter.NextPositions)
            {
                uiSquares[s.Row, s.Col].DrawFlashing();
                uiSquares[s.Row, s.Col].Flashing = true;
            }
        }

        public virtual void AnimationMove(Move move, Bitmap bmpBoard)
        {
            this.bmpBoard = bmpBoard;
            
            string strDir;
            if (fighter.Owner == Owner.White)
                strDir = appDir + "\\" + dirWFighter + "\\Move";
            else
                strDir = appDir + "\\" + dirBFighter + "\\Move";

            moveFrames = Directory.GetFiles(strDir).Length / 2; // img and reverse_img

            oldLocation = CalculateFighterCoordinate(move.OldRow, move.OldCol);
            newLocation = CalculateFighterCoordinate(move.NewRow, move.NewCol);
            fighter.Stance = Stance.Move;
            FighterMoveStepByStep();
        }

        public void RestoreHP()
        {
            // nothing for now
        }

        public void LevelUp(int increment)
        {
            // nothing for now
        }

        public void KilledBy(UIFighter killer)
        {
            // nothing to do right now
        }

        public void Fight(UIFighter enemy)
        {
            // nothing to do right now
        }

        public virtual void Draw() 
        {
            switch (fighter.Stance)
            {
                case Stance.Sit:
                    DrawSitStance();
                    break;
                case Stance.Stand:
                    DrawStandStance();
                    break;
                case Stance.Move:
                    DrawImg();
                    break;
                default: break;
            }
        }
        #endregion

        #region Event
        public delegate void EventRequestFlushBuffer();
        public event EventRequestFlushBuffer RequestFlushBuffer;
        public delegate void EventRequestDrawBoard();
        public event EventRequestDrawBoard RequestDrawBoard;

        void moveTimer_Tick_ActionMove(object sender, EventArgs e)
        {
            if (location.X == newLocation.X && location.Y > newLocation.Y) // move up
            {
                location.Y -= step;
                return;
            }
            else if (location.X == newLocation.X && location.Y < newLocation.Y) // move down
            {
                location.Y += step;
                return;
            }
            else if (location.Y == newLocation.Y && location.X > newLocation.X) // move left
            {
                location.X -= step;
                return;
            }
            else if (location.Y == newLocation.Y && location.X < newLocation.X) // move right
            {
                location.X += step;
                return;
            }
            else if (location.X < newLocation.X && location.Y < newLocation.Y) // move to bottom-right
            {
                location.X += step;
                //location.Y += step * deltaY / deltaX;
                location.Y += step;
                return;
            }
            else if (location.X < newLocation.X && location.Y > newLocation.Y) // move to top-right
            {
                location.X += step;
                //location.Y -= step * deltaY / deltaX;
                location.Y -= step;
                return;
            }
            else if (location.X > newLocation.X && location.Y < newLocation.Y) // move to bottom-left
            {
                location.X -= step;
                //location.Y += step * deltaY / deltaX;
                location.Y += step;
                return;
            }
            else if (location.X > newLocation.X && location.Y > newLocation.Y) // move to bottom-right
            {
                location.X -= step;
                //location.Y -= step * deltaY / deltaX;
                location.Y -= step;
                return;
            }

            // finish move
            location = newLocation;
            actionTimer.Tick -= new EventHandler(moveTimer_Tick_ActionMove);
            actionTimer.Enabled = false;
        }

        void imgTimer_Tick_ActionMove(object sender, EventArgs e)
        {
            if (!actionTimer.Enabled)
            {
                // reset value
                imgIndex = 0;
                imgTimer.Enabled = false;
                imgTimer.Tick -= new EventHandler(imgTimer_Tick_ActionMove);

                // set sit stance 
                fighter.Stance = Stance.Sit;
                DrawSitStance();

                // redraw board
                RequestDrawBoard();
                return;
            }

            imgIndex++;
            if (imgIndex == moveFrames)
                imgIndex = 1;
            string fileName = "";

            // check facing
            if (fighter.Facing == Facing.Left)
                fileName = "reverse_";

            // get filename by index
            if (imgIndex < 10)
                fileName += "0" + imgIndex.ToString();
            else
                fileName += imgIndex.ToString();

            fileName += ".png";

            // check owner
            if (fighter.Owner == Owner.White)
                fileName = appDir + "\\" + dirWFighter + "\\Move\\" + fileName;
            else
                fileName = appDir + "\\" + dirBFighter + "\\Move\\" + fileName;

            // draw
            img = new Bitmap(fileName);
            DrawMoveImg();
            RequestFlushBuffer();
        }
        #endregion

        #region Support Funcs
        protected Point CalculateFighterCoordinate(int row, int col)
        {
            Point result = new Point();
            result.X = col * width + 1;
            result.Y = (row + 1) * height - 1;
            result.Y += topReserve;

            return result;
        }

        public virtual void DrawStandStance() 
        { 
            if (fighter.Owner == Owner.White)
            {
                if (fighter.Facing == Facing.Right)
                    img = new Bitmap(
                        appDir + "\\" + dirWFighter + "\\" + "stand_face_right.png");
                else if (fighter.Facing == Facing.Left)
                    img = new Bitmap(
                        appDir + "\\" + dirWFighter + "\\" + "stand_face_left.png");

                DrawImg();
            }
            else if (fighter.Owner == Owner.Black)
            {
                if (fighter.Facing == Facing.Right)
                    img = new Bitmap(
                        appDir + "\\" + dirBFighter + "\\" + "stand_face_right.png");
                else if (fighter.Facing == Facing.Left)
                    img = new Bitmap(
                        appDir + "\\" + dirBFighter + "\\" + "stand_face_left.png");

                DrawImg();
            }
        }

        public virtual void DrawSitStance() 
        { 
            if (fighter.Owner == Owner.White)
            {
                if (fighter.Facing == Facing.Right)
                    img = new Bitmap(
                        appDir + "\\" + dirWFighter + "\\" + "sit_face_right.png");
                else if (fighter.Facing == Facing.Left)
                    img = new Bitmap(
                        appDir + "\\" + dirWFighter + "\\" + "sit_face_left.png");
            }
            else if (fighter.Owner == Owner.Black)
            {
                if (fighter.Facing == Facing.Right)
                    img = new Bitmap(
                        appDir + "\\" + dirBFighter + "\\" + "sit_face_right.png");
                else if (fighter.Facing == Facing.Left)
                    img = new Bitmap(
                        appDir + "\\" + dirBFighter + "\\" + "sit_face_left.png");
            }
            DrawImg();
        }

        protected void DrawImg()
        {
            //gOff.DrawImage((Image)img, location.X, location.Y - img.Height);

            ImageAttributes att = new ImageAttributes();
            att.SetColorKey(Color.FromArgb(255, 0, 255), Color.FromArgb(255, 0, 255));
            Rectangle destRect = new Rectangle(location.X, location.Y - img.Height, img.Width, img.Height);

            gOff.DrawImage((Image)img, destRect, 0, 0, img.Width, img.Height, GraphicsUnit.Pixel, att);
        }

        protected void DrawMoveImg()
        {
            // clear old pos (hinh chu thap!!!)
            Rectangle rect = new Rectangle(0, location.Y - img.Height - 3, bmpBoard.Width, img.Height + 6);
            gOff.DrawImage(bmpBoard, rect, rect, GraphicsUnit.Pixel);
            rect = new Rectangle(location.X - 3, 0, img.Width + 6, bmpBoard.Height);
            gOff.DrawImage(bmpBoard, rect, rect, GraphicsUnit.Pixel);

            // draw new pos
            DrawImg();
        }

        public Stack GetPoints(Point point1, Point point2)
        {
            Stack result = new Stack();
            ArrayList arrPoints = new ArrayList();

            int Dx = point2.X - point1.X;
            int Dy = point2.Y - point1.Y;

            int p = 2 * Dy - Dx;
            int const1 = 2 * Dy;
            int const2 = 2 * Dy - 2 * Dx;

            if (Math.Abs(Dy) > Math.Abs(Dx))
            {
                if (Dy < 0)
                {
                    Swap(ref point1, ref point2);
                }

                int x = point1.X;
                int y = point1.Y;

                for (int i = point1.Y; i <= point2.Y; i++)
                {
                    if (p < 0) p += const1;
                    else
                    {
                        p += const2;
                        if (point1.X != point2.X)
                            x++;
                    }
                    y++;

                    arrPoints.Add(new Point(x, y));
                }
            }
            else
            {
                if (Dx < 0)
                {
                    Swap(ref point1, ref point2);
                }

                int x = point1.X;
                int y = point1.Y;

                for (int i = point1.X; i <= point2.X; i++)
                {
                    if (p < 0) p += const1;
                    else
                    {
                        p += const2;
                        if (point1.Y != point2.Y)
                        y++;
                    }

                    x++;
                    arrPoints.Add(new Point(x, y));
                }
            }

            int index = arrPoints.Count - 1;
            while (index >= 0)
            {
                Point point = (Point)arrPoints[index];
                result.Push(new Point(point.X, point.Y));
                index--;
            }

            return result;
        }

        private void Swap(ref Point a, ref Point b)
        {
            Point temp = new Point(a.X, a.Y);

            a.X = b.X;
            a.Y = b.Y;

            b.X = temp.X;
            b.Y = temp.Y;
        }

        // action move
        private void FighterMoveStepByStep()
        {
            location = oldLocation;
            deltaX = Math.Abs(oldLocation.X - newLocation.X);
            deltaY = Math.Abs(oldLocation.Y - newLocation.Y);
            actionTimer.Interval = 125; // 8fps
            actionTimer.Tick += new EventHandler(moveTimer_Tick_ActionMove);

            imgTimer.Interval = 125; // ~16fps
            imgTimer.Tick += new EventHandler(imgTimer_Tick_ActionMove);

            actionTimer.Enabled = true;
            imgTimer.Enabled = true;
        }
        #endregion
    }
}
